/**
 * @file userTime.c
 * @brief
 * @author xuesong (wenshaoliu@foxmail.com)
 * @version 1.0
 * @date 2024-03-01
 *
 * @copyright Copyright (c) 2024  by xuesong
 *
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-03-01     <td>1.0     <td>xuesong   <td>内容
 * </table>
 */
#include "userTime.h"

static const char mon_list[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static const char leap_mon_list[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

/*******************************************************************************
 * Function Name : fun_mktime
 * Description   : 时间转为时间戳
 * Input         :
 * Output        :
 * Other         :
 * Date          : 2016.11.14
 *******************************************************************************/
int32_t user_mktime(struct ustm *pT)
{
  const char *pDays = NULL;
  int32_t tmp = 0;
  int16_t i = 0;

  // 计算总共有多少个闰年
  tmp = (pT->tm_year / 4 - pT->tm_year / 100 + pT->tm_year / 400) - (1970 / 4 - 1970 / 100 + 1970 / 400);

  // 如果当年是闰年，需要减去当年的闰年
  if ((pT->tm_year % 4 == 0) && ((pT->tm_year % 100 != 0) || (pT->tm_year % 400 == 0)))
  {
    tmp = tmp - 1 + (pT->tm_year - 1970) * 365;
    pDays = leap_mon_list;
  }
  else
  {
    tmp = tmp + (pT->tm_year - 1970) * 365;
    pDays = mon_list;
  }

  for (i = 0; i < pT->tm_mon - 1; i++)
    tmp += pDays[i];

  tmp = tmp + pT->tm_mday - 1;
  tmp = tmp * 24 + pT->tm_hour;
  tmp = tmp * 60 + pT->tm_min;
  tmp = tmp * 60 + pT->tm_sec;
  return tmp;
}

/*******************************************************************************
 * Function Name : fun_localtime
 * Description   : 时间戳转为时间
 * Input         :   struct tm *pT： 输出的时间缓冲区   uint32_t tim:当前时间戳
 * Output        :
 * Other         :
 * Date          : 2016.11.14
 *******************************************************************************/
void user_localtime(struct ustm *pT, int32_t tim)
{
  const char *pDays = NULL;
  uint16_t index = 0;
  memset(pT, 0, sizeof(*pT));
  pT->tm_wday = (tim / (24 * 60 * 60)) % 7 + 4;
  if (pT->tm_wday > 7)
    pT->tm_wday -= 7;
  // year initialization
  if (tim > 0x5685C180L) // 2016-1-1 0:0:0
  {
    pT->tm_year = 2016;
    tim -= 0x5685C180L;
  }
  else if (tim > 0x4B3D3B00L) // 2010-1-1 0:0:0
  {
    pT->tm_year = 2010;
    tim -= 0x4B3D3B00L;
  }

  else if (tim > 0x386D4380L) // 2000-1-1 0:0:0
  {
    pT->tm_year = 2000;
    tim -= 0x386D4380L;
  }
  else
  {
    pT->tm_year = 1970;
  }

  // now have year
  while (tim >= 366L * 24 * 60 * 60)
  {
    if ((pT->tm_year % 4 == 0) && ((pT->tm_year % 100 != 0) || (pT->tm_year % 400 == 0)))
      tim -= 366L * 24 * 60 * 60;
    else
      tim -= 365L * 24 * 60 * 60;

    pT->tm_year++;
  }

  // then 365 * 24 * 60 * 60 < tim < 366 * 24 * 60 * 60
  if (!(((pT->tm_year % 4 == 0) && ((pT->tm_year % 100 != 0) || (pT->tm_year % 400 == 0)))) && (tim > 365L * 24 * 60 * 60))
  {
    tim -= 365L * 24 * 60 * 60;
    pT->tm_year++;
  }

  // this year is a leap year?
  if (((pT->tm_year % 4 == 0) && ((pT->tm_year % 100 != 0) || (pT->tm_year % 400 == 0))))
    pDays = leap_mon_list;
  else
    pDays = mon_list;

  pT->tm_mon = 1;
  // now have mon
  while (tim > pDays[index] * 24L * 60 * 60)
  {
    tim -= pDays[index] * 24L * 60 * 60;
    index++;
    pT->tm_mon++;
  }

  // now have days
  pT->tm_mday = tim / (24L * 60 * 60) + 1;
  tim = tim % (24L * 60 * 60);

  // now have hour
  pT->tm_hour = tim / (60 * 60);
  tim = tim % (60 * 60);

  // now have min
  pT->tm_min = tim / 60;
  tim = tim % 60;

  pT->tm_sec = tim;
}

const u8 days_per_month[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
FIND_LEAP_YEAR rtc_calLeapYear(u16 year)
{

  if ((year % 100) == 0)
  {
    if ((year % 400) == 0)
    {
      return LEAP_YEAR;
    }
    else
    {
      return NONLEAP_YEAR;
    }
  }
  else
  {
    if ((year % 4) == 0)
    {
      return LEAP_YEAR;
    }
    else
    {
      return NONLEAP_YEAR;
    }
  }
}
/**
 * @brief
 * @param  curTime          MyParamDoc
 * @param  sec             	sec cnt from start year/1/1 0:0:0
 */
#define START_YEAR 2024
#define START_WEEK WEEK_MONDAY
void rtc_calSysTimeBySecond(rtc_format_t *curTime, u64 sec)
{
  u16 year = START_YEAR;
  u16 dayAdd = 0;
  u8 isLeap = 0;
  u32 totalDay = sec / TOTAL_SECOND_PER_DAY;
  u32 curDay = 0;
  u32 secOneDay = sec % TOTAL_SECOND_PER_DAY;

  curTime->totalSecond = sec;

  while (1)
  {
    isLeap = rtc_calLeapYear(year);
    dayAdd = ((isLeap == LEAP_YEAR) ? 366 : 365);
    curDay = curDay + dayAdd;
    year++;
    if (curDay > totalDay)
    {
      year--;
      curDay -= dayAdd;
      break;
    }
  }

  curTime->year = year;
  totalDay -= curDay;

  dayAdd = curDay = 0;
  isLeap = rtc_calLeapYear(year);

  while (1)
  {
    curDay += days_per_month[dayAdd];
    if (dayAdd == 2)
    { /// days_per_month[2] + isLeap
      curDay += isLeap;
    }

    if (curDay > totalDay)
    {
      curDay -= days_per_month[dayAdd];
      if (dayAdd == 2)
      {
        curDay -= isLeap;
      }
      break;
    }
    dayAdd++;
  }
  curTime->month = dayAdd;
  curTime->day = totalDay - curDay + 1;
  curTime->hour = (u8)(secOneDay / TOTAL_SECOND_PER_HOUR);
  curTime->min = (secOneDay % TOTAL_SECOND_PER_HOUR) / TOTAL_SECOND_PER_MIN;
  curTime->second = (secOneDay % TOTAL_SECOND_PER_MIN);

  /// 2010.1.1 is Friday
  curTime->week = ((START_WEEK) ? START_WEEK - 1 : WEEK_SUNDAY + ((sec / TOTAL_SECOND_PER_DAY + 1) % 7)) % 7;
}

#include "stdlib.h"
#include "stdio.h"
uint32_t clock_time(void)
{
  static uint32_t lastTickCnt = 0;
  // lastTickCnt += rand() * 25679;
  printf("input tick:");
  scanf("%d", &lastTickCnt);
  return lastTickCnt;
}

uint32_t time_tick = 0;
uint8_t tickCnt = 0;
uint16_t MainHalfSecondCnt = 0;
ClockFlag_t ProcessClock(void)
{
  uint32_t subTimeTick;
  uint32_t _16msTick;
  ClockFlag_t clockFlag = {
      .Byte = 0,
  };
  uint32_t currentTimeTick = clock_time();
  if (currentTimeTick >= time_tick)
  {
    subTimeTick = currentTimeTick - time_tick;
  }
  else
  {
    subTimeTick = currentTimeTick + ~(time_tick) + 1;
  }
  _16msTick = subTimeTick / 256000;
  if (_16msTick)
  {
    time_tick += _16msTick * 256000;
    while (_16msTick--)
    {
      tickCnt++;
      clockFlag.Bits._16MS = true;
      if (tickCnt & 0x01)
        clockFlag.Bits._32MS = 1;
      if ((tickCnt & 0x03) == 0x03)
        clockFlag.Bits._64MS = 1;
      if ((tickCnt & 0x07) == 0x07)
        clockFlag.Bits._128MS = 1;
      if ((tickCnt & 0x0F) == 0x0F)
        clockFlag.Bits._256MS = 1;
      if ((tickCnt & 0x1F) == 0x1F)
      {
        clockFlag.Bits.HalfSecond = 1;
        MainHalfSecondCnt++;
      }
      if ((tickCnt & 0x3F) == 0x3F)
        clockFlag.Bits.Second = 1;
    }
  }
  // if (taskFunc_rtcEvent())
  // {
  //     // clockFlag.Bits.Second = 1;
  // }
  return clockFlag;
}

void testClock(void)
{
  ClockFlag_t clockFlag = ProcessClock();
  if (clockFlag.Bits.HalfSecond)
  {
    printf("halfSecond trigger main_half=%d,tick=%d\r\n", MainHalfSecondCnt, time_tick);
  }
}